package me.keiwu.pub.util;

import org.joda.time.DateTime;
import org.joda.time.Days;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * <b><code>DateUtils</code></b>
 * <p>
 * date utils
 * </p>
 * <b>Creation Time:</b> 2015年4月14日 下午5:11:21
 * @author kext
 * @since dwf 1.0
 */
public final class DateUtil {

	private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);

	public static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";
	public static final String DEFAULT_PATTERN2 = "yyyy/MM/dd HH:mm:ss";

	public static final String TIME_PATTERN = "HH:mm:ss";

	public static final String DEFAULT_PATTERN_WITHOUT_SECOND = "yyyy-MM-dd HH:mm";

	public static final String DATE_PATTERN = "yyyy-MM-dd";

	public static final String DATE_PATTERN_CHINESE = "yyyy年MM月dd日";

	/**
	 * 
	 * format date by given pattern
	 *
	 * @param date
	 * @param pattern
	 * @return
	 * @since dwf 1.0
	 */
	public static String formatDate(final Date date, String pattern) {
		return formatDate(date, pattern, Locale.CHINA);
	}

	public static String formatDate(final Date date, String pattern, Locale locale) {
		if (date == null) {
			return null;
		}
		if (pattern == null) {
			pattern = DEFAULT_PATTERN;
		}
		final SimpleDateFormat formatter = new SimpleDateFormat(pattern, locale);
		return formatter.format(date);
	}

	public static String formatDateTime(final Date date) {
		final SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_PATTERN);
		return formatter.format(date);
	}

	public static String formatDate(final Date date) {
		if (null == date) {
			return "";
		}
		final SimpleDateFormat formatter = new SimpleDateFormat(DATE_PATTERN);
		return formatter.format(date);
	}

	public static String formatTime(final Date date) {
		if (null == date) {
			return "";
		}
		final SimpleDateFormat formatter = new SimpleDateFormat(TIME_PATTERN);
		return formatter.format(date);
	}

	public static String formatTime(final Date date, String pattern) {
		if (null == date) {
			return "";
		}
		final SimpleDateFormat formatter = new SimpleDateFormat(pattern);
		return formatter.format(date);
	}

	public static Date parseDate(final String date) {
		final SimpleDateFormat formatter = new SimpleDateFormat(DATE_PATTERN);
		try {
			return formatter.parse(date);
		} catch (ParseException e) {
			logger.error("Parse Exception, date={}, pattern={}", date, DATE_PATTERN, e);
			return null;
		}
	}

	public static Date parseDate(final String date, String pattern) {
		if (pattern == null) {
			pattern = DATE_PATTERN;
		}
		final SimpleDateFormat formatter = new SimpleDateFormat(pattern);
		try {
			return formatter.parse(date);
		} catch (ParseException e) {
			logger.error("Parse Exception, date={}, pattern={}", date, pattern, e);
			return null;
		}
	}

	public static Date parseTime(final String time) {

		final SimpleDateFormat formatter = new SimpleDateFormat(TIME_PATTERN);
		try {
			return formatter.parse(time);
		} catch (ParseException e) {
			logger.error("Parse Exception, date={}, pattern={}", time, TIME_PATTERN, e);
			return null;
		}
	}

	public static Date parseDateTime(final String dateTime) {
		return parseDate(dateTime, DEFAULT_PATTERN);
	}

	public static Date parseDate(final Long timestamp) {
		SimpleDateFormat format = new SimpleDateFormat(DATE_PATTERN);
		String date = format.format(timestamp);
		try {
			return format.parse(date);
		} catch (ParseException e) {
			logger.error("Parse Exception, timestamp={}", timestamp, e);
			return null;
		}
	}
	
	public static Date parseDate(final Long timestamp, String pattern) {
		SimpleDateFormat format = new SimpleDateFormat(pattern);
		String date = format.format(timestamp);
		try {
			return format.parse(date);
		} catch (ParseException e) {
			logger.error("Parse Exception, timestamp={}", timestamp, e);
			return null;
		}
	}

	public static int calculateAge(Date date) {
		if (date == null) {
			return 0;
		}
		LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
		Long age = localDate.until(LocalDate.now(), ChronoUnit.YEARS);
		return age.intValue();
	}

	public static boolean isWeekend(Date date) {
		if (date == null) {
			return false;
		}
		LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
		return localDate.getDayOfWeek() == DayOfWeek.SATURDAY || localDate.getDayOfWeek() == DayOfWeek.SUNDAY;
	}

	/**
	 * 
	 * 计算明天，跳过周末
	 *
	 * @param date
	 * @return
	 * @since dwf 1.0
	 */
	public static Date calcTmrByPassingWeekend(Date date) {
		LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
		LocalDate tmrLocalDate = null;
		switch (localDate.getDayOfWeek().getValue()) {
		case 5:
			tmrLocalDate = localDate.plusDays(3);
			break;
		case 6:
			tmrLocalDate = localDate.plusDays(2);
			break;
		default:
			tmrLocalDate = localDate.plusDays(1);
			break;
		}
		return Date.from(tmrLocalDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
	}

	public static Date addDays(Date date, int amount) {
		return org.apache.commons.lang.time.DateUtils.addDays(date, amount);
	}

	public static Date toDateTime(Date date, String time) {
		try {
			return new SimpleDateFormat(DEFAULT_PATTERN).parse(formatDate(date) + " " + time);
		} catch (ParseException e) {
			logger.error(
					"To datetime Exception, date={}, time={}", date, time, e);
			return null;
		}
	}

	public static Date toDateTimeWithoutSecond(Date date, String time) {
		try {
			return new SimpleDateFormat(DEFAULT_PATTERN_WITHOUT_SECOND).parse(formatDate(date) + " " + time);
		} catch (ParseException e) {
			logger.error("To datetime without second Exception, date={}, time={}", date, time, e);
			return null;
		}
	}

	public static boolean isSameDay(Date date1, Date date2) {
		if (date1 == null || date2 == null) return false;
		return org.apache.commons.lang.time.DateUtils.isSameDay(date1, date2);
	}

	public static Date addHours(final Date date, final int amount) {
		return org.apache.commons.lang.time.DateUtils.addHours(date, amount);
	}

	public static Date addMinutes(final Date date, final int amount) {
		return org.apache.commons.lang.time.DateUtils.addMinutes(date, amount);
	}
	
	public static Date addYears(final Date date, final int amount) {
		return org.apache.commons.lang.time.DateUtils.addYears(date, amount);
	}

	/**
	 * 
	 * 计算两个日期相差天数
	 *
	 * @param date1
	 * @param date2
	 * @return 正数，date1 > date2
	 * @since dwf 1.0
	 */
	public static int calculateDateGap(Date date1, Date date2) {
		DateTime dt1 = new DateTime(date1);
		DateTime dt2 = new DateTime(date2);
		return Days.daysBetween(dt2, dt1).getDays();
	}

	/**
	 * 
	 * 获取当天的时间, 时分秒为0
	 *
	 * @return
	 * @since dwf 1.0
	 */
	public static Date getCurrentDay() {
		return clearHHmmss(new Date());
	}

	public static Date getDayStart(Date date) {
		return clearHHmmss(date);
	}

	public static Date getDayStart(long time) {
		return clearHHmmss(new Date(time));
	}

	public static Date getDayEnd(Date date) {
		return addHours(getDayStart(date), 24);
	}

	/**
	 * 获取当前时间，包括时分秒
	 * @return
	 * @date 2015年10月19日
	 * @author xuan
	 */
	public static Date getCurrentTime() {
		return new Date();
	}
	
	public static long calculateDateGap(long date1, long date2) {
		return calculateDateGap(new Date(date1), new Date(date2));
	}
	
	/**
	 * 获取当前时点
	 * @param date
	 * @return
	 */
	public static int getHourOfDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * 获取当前时分
	 * @param date
	 * @return
	 */
	public static int getMinuteOfDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int h = calendar.get(Calendar.HOUR_OF_DAY);
		int m = calendar.get(Calendar.MINUTE);
		return h * 60 + m;
	}
	
	public static Date clearHHmmss(Date date) {
		Calendar ca = Calendar.getInstance();
		ca.setTime(date);
		ca.set(Calendar.HOUR_OF_DAY, 0);
		ca.set(Calendar.MINUTE, 0);
		ca.set(Calendar.SECOND, 0);
		ca.set(Calendar.MILLISECOND, 0);
		return ca.getTime();
	}

	/**
	 * 
	 * 相隔天数 真实间隔,计算上时分秒
	 * 
	 * @return
	 */
	public static int betweenDays(Date dateMin, Date dateMax) {
		return (int) ((dateMax.getTime() - dateMin.getTime()) / 1000 / 3600 / 24);
	}

	/**
	 *
	 * 相隔天数
	 *
	 * @return
	 */
	public static int daysGap(Date dateMin, Date dateMax) {
		return DateUtil.betweenDays(DateUtil.parseDate(dateMin.getTime()), DateUtil.parseDate(dateMax.getTime())) + 1;
	}

	/**
	 * 相隔天数，不考虑时分秒
	 *
	 * @param startDate
	 * @param endDate
	 * @return
	 * @since dwf 1.1
	 */
	public static int betweenDaysIgnoreTime(Date startDate, Date endDate) {
		Calendar fromCalendar = Calendar.getInstance();  
        fromCalendar.setTime(startDate);
        fromCalendar.set(Calendar.HOUR_OF_DAY, 0);  
        fromCalendar.set(Calendar.MINUTE, 0);  
        fromCalendar.set(Calendar.SECOND, 0); 
  
        Calendar toCalendar = Calendar.getInstance();  
        toCalendar.setTime(endDate);  
        toCalendar.set(Calendar.HOUR_OF_DAY, 0);  
        toCalendar.set(Calendar.MINUTE, 0);  
        toCalendar.set(Calendar.SECOND, 1);  
  
        return Math.abs((int)((toCalendar.getTimeInMillis() - fromCalendar.getTimeInMillis()) / 1000 / 3600 / 24));  
	}
	
	/**
	 * 获取当前时间戳
	 * 
	 * @return 返回秒数
	 */
	public static int getUnixTime() {
		long unixTime = System.currentTimeMillis() / 1000;
		return (int) unixTime;
	}
	
	/**
	 * 获取时间戳
	 * 
	 * @return 返回秒数
	 */
	public static int getUnixTime(Date date) {
		long unixTime = date.getTime() / 1000;
		return (int) unixTime;
	}
	
	/**
	 * GMT时间字符串转Date
	 * @param gmtTime
	 * @return
	 * @date 2015年10月21日
	 * @author xuan
	 */
	public static Date gmtTimeStringToDate(String gmtTime) {
		DateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);  
		format.setTimeZone(TimeZone.getTimeZone("GMT"));
		Date date = null;
		try {
			date = format.parse(gmtTime);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}
	
	/**
	 * 去掉日期，只留下时分秒
	 *
	 * @param date
	 * @return
	 * <b>Creation Time:</b> 2015年11月24日 下午12:07:29
	 * @author xuan
	 * @since dwf 1.1
	 */
	public static Date clearYYMMDD(Date date) {
		return parseDate(formatDate(date, "HH:mm:ss"), "HH:mm:ss");
	}
	
	/**
	 * 去掉日期, 只判断时分秒, targetTime是在minTime和maxTime之间
	 *
	 * @param targetTime
	 * @param minTime
	 * @param maxTime
	 * @return
	 * <b>Creation Time:</b> 2015年11月27日 下午6:28:18
	 * @author xuan
	 * @since dwf 1.1
	 */
	public static boolean betweenTime(Date targetTime, Date minTime, Date maxTime) {
		long time = clearYYMMDD(targetTime).getTime();
		return clearYYMMDD(minTime).getTime() <= time && time <= clearYYMMDD(maxTime).getTime();
	}
	
	/**
	 * 去掉时分秒, 只判断日期, targetDate是在minDate和maxDate之间
	 *
	 * @param targetDate
	 * @param minDate
	 * @param maxDate
	 * @return
	 * <b>Creation Time:</b> 2016年1月5日 下午2:52:39
	 * @author xuan
	 * @since dwf 1.1
	 */
	public static boolean betweenDate(Date targetDate, Date minDate, Date maxDate) {
		long time = clearHHmmss(targetDate).getTime();
		return clearHHmmss(minDate).getTime() <= time && time <= clearHHmmss(maxDate).getTime();
	}
	
	/**
	 * target是否在[min,max]
	 *
	 * @param target
	 * @param min
	 * @param max
	 * @return
	 * <b>Creation Time:</b> 2015年12月25日 下午5:07:40
	 * @author xuan
	 * @since dwf 1.1
	 */
	public static boolean between(Date target, Date min, Date max) {
		return min.getTime() <= target.getTime() && target.getTime() <= max.getTime();
    }
	
    /**
	 * 只要时分
	 *
	 * @param date
	 * @return
	 * <b>Creation Time:</b> 2016年1月3日 上午2:32:41
	 * @author xuan
	 * @since dwf 1.1
	 */
	public static Date getHHmm(Date date) {
		Date tmp = clearYYMMDD(date);
		Calendar ca = Calendar.getInstance();
		ca.setTime(tmp);
		ca.set(Calendar.SECOND, 0);
		ca.set(Calendar.MILLISECOND, 0);
		return ca.getTime();
	}

	public static LocalDate toLocalDate(Date date) {
		Instant instant = Instant.ofEpochMilli(date.getTime());
		LocalDate locatDate = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).toLocalDate();
		return locatDate;
	}

	public static LocalTime toLocalTime(Date date) {
		Instant instant = Instant.ofEpochMilli(date.getTime());
		LocalTime locatTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).toLocalTime();
		return locatTime;
	}

	public static LocalDateTime toLocalDateTime(Date date) {
		Instant instant = Instant.ofEpochMilli(date.getTime());
		LocalDateTime locatDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
		return locatDateTime;
	}

	public static Date toDate(LocalDate localDate) {
		Instant instant = localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
		Date date = Date.from(instant);
		return date;
	}

	public static Date toDate(LocalDateTime localDateTime) {
		Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
		Date date = Date.from(instant);
		return date;
	}
	
	/**
	 * 计算分钟差
	 *
	 * @param minTime
	 * @param timezone1 时区
	 * @param maxTime
	 * @param timezone2 时区
	 * @return
	 * <b>Creation Time:</b> 2016年1月31日 下午5:23:15
	 * @author xuan
	 * @since dwf 1.1
	 */
	public static int calcMinuteGap(Date minTime, int timezone1, Date maxTime, int timezone2) {
		int minuteGap = (int) (calcMillisSecondGap(minTime.getTime(), timezone1, maxTime.getTime(), timezone2) / (60 * 1000));//毫秒转分
		return minuteGap;
	}
	
	/**
	 * 计算秒差
	 *
	 * @param minMillisTime
	 * @param timezone1 时区
	 * @param maxMillisTime
	 * @param timezone2 时区
	 * @return
	 * <b>Creation Time:</b> 2016年2月18日 上午11:08:26
	 * @author xuan
	 * @since dwf 1.1
	 */
	public static int calcSecondGap(long minMillisTime, int timezone1, long maxMillisTime, int timezone2) {
		int secondGap = (int) (calcMillisSecondGap(minMillisTime, timezone1, maxMillisTime, timezone2) / 1000);//毫秒转秒
		return secondGap;
	}
	/**
	 * 计算毫秒差
	 *
	 * @param minMillisTime
	 * @param timezone1 时区
	 * @param maxMillisTime
	 * @param timezone2 时区
	 * @return
	 * <b>Creation Time:</b> 2016年2月18日 上午10:50:14
	 * @author xuan
	 * @since dwf 1.1
	 */
	public static long calcMillisSecondGap(long minMillisTime, int timezone1, long maxMillisTime, int timezone2) {
		//先统一转为北京时间毫秒数
		long time1 = getBeijingMillisTime(minMillisTime, timezone1);
		long time2 = getBeijingMillisTime(maxMillisTime, timezone2);
		long millisSecondGap = time2 - time1;
		return millisSecondGap;
	}
	
	private static long getBeijingMillisTime(long millisTime, int timezone) {
		int beijingTimezone = 8;
		if(timezone == beijingTimezone) {
			return millisTime;
		}
		
		Calendar c = Calendar.getInstance();
		c.setTimeInMillis(millisTime);
		c.add(Calendar.HOUR_OF_DAY, beijingTimezone - timezone);
		return c.getTimeInMillis();
	}
	
	public static Date getMaxDate(Date date1, Date date2) {
		return date1.after(date2) ? date1 : date2;
	}
	
	public static Date getMinDate(Date date1, Date date2) {
		return date1.after(date2) ? date2 : date1;
	}

	/**
	 * 获取星期，1-6:星期一到六，0：星期日
	 *
	 * @param date
	 * @return
	 * <b>Creation Time:</b> 2016年3月7日 下午4:23:36
	 * @author xuan
	 * @since dwf 1.1
	 */
	public static int getDayOfWeek(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		return c.get(Calendar.DAY_OF_WEEK);
	}

	public static int getDayOfYear(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		return c.get(Calendar.DAY_OF_YEAR);
	}
	
	public static String toUTCString(Date date) {
		DateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss", Locale.US);         
		format.setTimeZone(TimeZone.getTimeZone("GMT-0"));         
		StringBuilder sb = new StringBuilder();
		sb.append(format.format(date));
		sb.append(" UTC");
		return sb.toString();
	}


	public static int getDayStrInt(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		int year = c.get(Calendar.YEAR);
		int month = c.get(Calendar.MONTH) + 1;
		int day = c.get(Calendar.DAY_OF_MONTH);
		return year*10000 + month*100 + day;
	}


	public static void main(String[] args) {
//		System.out.println(DateUtils.parseDate(DateUtils.parseDate("2016-05-07 10:50:00").getTime()));
//		System.out.println(DateUtils.parseDate(DateUtils.parseDate("2016-05-17 08:45:00").getTime()));
//		System.out.println(DateUtils.betweenDays(DateUtils.parseDate(DateUtils.parseDate("2016-05-07 10:50:00").getTime()), DateUtils.parseDate(DateUtils.parseDateTime("2016-05-17 08:45:00").getTime())));

//		Integer weekNum = getDayOfWeek(new Date());
//		System.out.println(weekNum);
//		Date maxTime = parseDate("2016-03-17 10:00:00");
		//System.out.println(calcMinuteGap(minTime, 8, maxTime, 7));
//		System.out.println(-daysGap(Date.from(Instant.now()), maxTime));
		//System.out.println(DateUtils.formatDateTime(new Date(1484323160000l)));


		System.err.println(DateUtil.getDayStrInt(new Date()));
		System.err.println(DateUtil.getDayStrInt(DateUtil.addDays(new Date(), -3)));
	}
}
